package com.ruoyi.system.service.impl;

import com.alibaba.fastjson2.util.DateUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.system.domain.Project;
import com.ruoyi.system.entity.ContractDO;
import com.ruoyi.system.dto.ProjectDTO;
import com.ruoyi.system.dto.ProjectDynamicDTO;
import com.ruoyi.system.dto.ProjectStagePointDTO;
import com.ruoyi.system.dto.ProgressCountDTO;
import com.ruoyi.system.dto.ProjectQueryDTO;
import com.ruoyi.system.dto.convert.ProjectConvert;
import com.ruoyi.system.mapper.ProjectMapper;
import com.ruoyi.system.mapper.ContractMapper;
import com.ruoyi.system.service.ProjectService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.Collections;
import java.util.stream.Stream;

/**
 * 项目服务实现类
 */
@Service
public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> implements ProjectService {

    @Resource
    private ProjectMapper projectMapper;
    @Resource
    private ContractMapper contractMapper;

    @Override
    @Transactional
    public ProjectDTO createProject(ProjectDTO projectDTO) {
        // 验证期房日期
        validateFutureHouseDate(projectDTO);

        // 生成项目编号
        String projectNo = generateProjectNo();
        projectDTO.setProjectNo(projectNo);

        // 生成项目名称：客户名称 - 小区名称 - 户型
        String projectName = generateProjectName(projectDTO);
        projectDTO.setProjectName(projectName);

        // 获取当前登录用户信息
        Long currentUserId = SecurityUtils.getUserId();
        String currentUserName = SecurityUtils.getUsername();

        // 如果未指定设计师，默认设置为当前用户（如果当前用户是设计师）
        if (projectDTO.getDesignerId() == null) {
            if (SecurityUtils.hasRole("DESIGNER")) {
                projectDTO.setDesignerId(currentUserId);
                projectDTO.setDesignerName(currentUserName);
            }
        }

        h5UserCheck(projectDTO);

        if (projectDTO.getConstructionProjectId() != null) {
            if (this.lambdaQuery()
                    .eq(Project::getConstructionProjectId, projectDTO.getConstructionProjectId())
                    .notIn(Project::getProgress, 7,8)
                    .exists()) {
                throw new ServiceException("该施工项目已绑定其他未完成项目");
            }
        }

        // 转换DTO为实体
        Project project = convertToEntity(projectDTO);
        project.setCreateBy(currentUserId);
        project.setUpdateBy(currentUserId);

        // 保存项目
        baseMapper.insert(project);

        // 转换实体为DTO并返回
        return ProjectConvert.INSTANCE.convert(project);
    }

    @Override
    @Transactional
    public ProjectDTO updateProject(Long id, ProjectDTO projectDTO) {
        // 验证项目是否存在
        Project existingProject = baseMapper.selectById(id);
        if (existingProject == null || existingProject.getDeleted() == 1) {
            throw new ServiceException("项目不存在或已被删除");
        }

        // 验证权限
        validatePermission(existingProject);

        // 验证期房日期
        validateFutureHouseDate(projectDTO);

        // 更新项目名称（如果客户名称、小区名称或户型有变化）
        if (isProjectNameChanged(existingProject, projectDTO)) {
            String projectName = generateProjectName(projectDTO);
            projectDTO.setProjectName(projectName);
        }
        if (existingProject.getH5UserId() == null ||
                (projectDTO.getH5UserId() != null && !existingProject.getH5UserId().equals(projectDTO.getH5UserId()))) {
            h5UserCheck(projectDTO);
        }

        // 转换DTO为实体
        Project project = convertToEntity(projectDTO);
        project.setId(id);
        project.setProjectNo(existingProject.getProjectNo()); // 项目编号不可修改
        project.setUpdateBy(SecurityUtils.getUserId());

        if (projectDTO.getConstructionProjectId() != null &&
                (existingProject.getConstructionProjectId() == null ||
                        !existingProject.getConstructionProjectId().equals(projectDTO.getConstructionProjectId()))) {
            if (this.lambdaQuery()
                    .eq(Project::getConstructionProjectId, projectDTO.getConstructionProjectId())
                    .notIn(Project::getProgress, 7,8)
                    .exists()) {
                throw new ServiceException("该施工项目已绑定其他未完成项目");
            }
        }
        // 更新项目
        baseMapper.updateById(project);

        // 转换实体为DTO并返回
        return ProjectConvert.INSTANCE.convert(baseMapper.selectById(id));
    }

    private void h5UserCheck(ProjectDTO projectDTO) {
        if (projectDTO.getBindH5Account() != null && projectDTO.getBindH5Account() == 1) {
            if (projectDTO.getH5UserId() == null) {
                throw new ServiceException("绑定H5账号时，H5用户ID不能为空");
            }
            if (this.lambdaQuery()
                    .eq(Project::getH5UserId, projectDTO.getH5UserId())
                    .ne(Project::getProgress, 8)
                    .exists()) {
                throw new ServiceException("该H5用户已绑定其他未完成项目");
            }
        }
    }

    @Override
    @Transactional
    public boolean deleteProject(Long id) {
        // 验证管理员权限
        if (!SecurityUtils.hasRole("ADMIN")) {
            throw new ServiceException("只有管理员可以删除项目");
        }

        // 验证项目是否存在
        Project project = baseMapper.selectById(id);
        if (project == null || project.getDeleted() == 1) {
            throw new ServiceException("项目不存在或已被删除");
        }

        // 逻辑删除项目
        return baseMapper.deleteById(id) > 0;
    }

    @Override
    public ProjectDTO getProjectById(Long id) {
        Project project = baseMapper.selectById(id);
        if (project == null || project.getDeleted() == 1) {
            throw new ServiceException("项目不存在或已被删除");
        }

        // 验证权限
//        validatePermission(project);

        return ProjectConvert.INSTANCE.convert(project);
    }

    @Override
    public ProjectDTO getProjectByIdNoValidatePermission(Long id) {
        Project project = baseMapper.selectById(id);
        if (project == null || project.getDeleted() == 1) {
            throw new ServiceException("项目不存在或已被删除");
        }
        return ProjectConvert.INSTANCE.convert(project);
    }

    @Override
    public IPage<ProjectDTO> queryProjectPage(ProjectQueryDTO queryDTO) {
        // 获取当前用户信息
        boolean isAdmin = SecurityUtils.hasRole("ADMIN");
        Long currentUserId = SecurityUtils.getUserId();
//        boolean isAdmin = true;
//        Long currentUserId = 1L;

        // 分页查询
        Page<Project> page = new Page<>(queryDTO.getPageNum(), queryDTO.getPageSize());
        IPage<Project> projectPage = projectMapper.queryProjectPage(page, queryDTO, isAdmin, currentUserId);

        // 转换为DTO分页对象并返回
        return projectPage.convert(ProjectConvert.INSTANCE::convert);
    }

    @Override
    public String generateProjectNo() {
        // 生成项目编号：AB-yyyyMMdd-XXX
        String specifiedDate = DateUtils.format(LocalDate.now(), "yyyyMMdd");

        String prefix = "AB-" + specifiedDate + "-";

        Integer maxSeq = projectMapper.getMaxProjectCodeSeq(specifiedDate);

        String num = String.format("%03d", (maxSeq == null ? 1 : maxSeq + 1));

        return prefix + num;
    }

    @Override
    public long countSignedButNotStarted() {
        // 取出审核通过的合同对应的项目ID集合（按数据范围过滤）
        List<Long> signedProjectIds = contractMapper.selectList(
                        new LambdaQueryWrapper<ContractDO>()
                                .eq(ContractDO::getIsDeleted, 0)
                                .eq(ContractDO::getAuditStatus, 2)
                                .select(ContractDO::getProjectId)
                )
                .stream()
                .map(ContractDO::getProjectId)
                .filter(Objects::nonNull)
                .distinct()
                .collect(Collectors.toList());

        if (signedProjectIds.isEmpty()) {
            return 0L;
        }

        LambdaQueryWrapper<Project> wrapper = new LambdaQueryWrapper<Project>()
                .in(Project::getId, signedProjectIds)
                .notIn(Project::getProgress, 6,7,8)
                .eq(Project::getDeleted, 0);
        if (!SecurityUtils.hasRole("ADMIN")) {
            wrapper.eq(Project::getDesignerId, SecurityUtils.getUserId());
        }
        return this.count(wrapper);
    }

    @Override
    public long countPendingSign() {
        // 找出现有有效合同的项目ID
        Set<Long> projectIdsWithContract = contractMapper.selectList(
                        new LambdaQueryWrapper<ContractDO>()
                                .eq(ContractDO::getIsDeleted, 0)
                                .select(ContractDO::getProjectId)
                )
                .stream()
                .map(ContractDO::getProjectId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());

        // 待签：项目未结单(progress != 8)、未删除，且不在“有合同”的集合中（按数据范围过滤）
        LambdaQueryWrapper<Project> wrapper = new LambdaQueryWrapper<Project>()
                .ne(Project::getProgress, 8)
                .eq(Project::getDeleted, 0);
        if (!projectIdsWithContract.isEmpty()) {
            wrapper.notIn(Project::getId, projectIdsWithContract);
        }
        if (!SecurityUtils.hasRole("ADMIN")) {
            wrapper.eq(Project::getDesignerId, SecurityUtils.getUserId());
        }
        return this.count(wrapper);
    }

    @Override
    public long countStartedProjects() {
        LambdaQueryWrapper<Project> wrapper = new LambdaQueryWrapper<Project>()
                .eq(Project::getDeleted, 0)
                .eq(Project::getProgress, 6);
        if (!SecurityUtils.hasRole("ADMIN")) {
            wrapper.eq(Project::getDesignerId, SecurityUtils.getUserId());
        }
        return this.count(wrapper);
    }

    @Override
    public long countFinishedProjects() {
        LambdaQueryWrapper<Project> wrapper = new LambdaQueryWrapper<Project>()
                .eq(Project::getDeleted, 0)
                .in(Project::getProgress, 7, 8);
        if (!SecurityUtils.hasRole("ADMIN")) {
            wrapper.eq(Project::getDesignerId, SecurityUtils.getUserId());
        }
        return this.count(wrapper);
    }

    

    @Override
    public IPage<ProjectDynamicDTO> queryProjectDynamics(int pageNum, int pageSize, String keyword) {
        Page<Project> page = new Page<>(pageNum, pageSize);
        LambdaQueryWrapper<Project> wrapper = new LambdaQueryWrapper<Project>()
                .eq(Project::getDeleted, 0);
        if (keyword != null && !keyword.trim().isEmpty()) {
            wrapper.and(w -> w.like(Project::getProjectName, keyword)
                    .or().like(Project::getDetailAddress, keyword)
                    .or().like(Project::getCommunityName, keyword));
        }
        if (!SecurityUtils.hasRole("ADMIN") && !SecurityUtils.hasRole("ROLE_ADMIN")) {
            wrapper.eq(Project::getDesignerId, SecurityUtils.getUserId());
        }
        IPage<Project> projectPage = this.page(page, wrapper);

        // 预取所有项目ID
        List<Long> projectIds = projectPage.getRecords().stream().map(Project::getId).collect(Collectors.toList());
        // 合同金额聚合（仅未删除，可选审核通过）
        final Map<Long, BigDecimal> contractSumMap;
        if (!projectIds.isEmpty()) {
            contractSumMap = contractMapper.selectList(new LambdaQueryWrapper<ContractDO>()
                            .eq(ContractDO::getIsDeleted, 0)
                            .in(ContractDO::getProjectId, projectIds)
                            .select(ContractDO::getProjectId, ContractDO::getSignedAmount))
                    .stream()
                    .filter(c -> c.getProjectId() != null && c.getSignedAmount() != null)
                    .collect(Collectors.groupingBy(ContractDO::getProjectId,
                            Collectors.mapping(ContractDO::getSignedAmount,
                                    Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))));
        } else {
            contractSumMap = Collections.emptyMap();
        }

        return projectPage.convert(p -> {
            ProjectDynamicDTO dto = new ProjectDynamicDTO();
            dto.setProjectId(p.getId());
            dto.setProjectName(p.getProjectName());
            String address = Stream.of(
                    nullToEmpty(p.getProvince()),
                    nullToEmpty(p.getCity()),
                    nullToEmpty(p.getDistrict()),
                    nullToEmpty(p.getDetailAddress())
            ).filter(s -> !s.isEmpty()).collect(Collectors.joining(" "));
            dto.setSiteAddress(address);
            dto.setProgress(p.getProgress());
            dto.setProgressName(progressName(p.getProgress()));
            dto.setContractTotalAmount(contractSumMap.getOrDefault(p.getId(), BigDecimal.ZERO));
            // 变更总费用、收款金额暂不填充，保持为null
            return dto;
        });
    }

    private String nullToEmpty(String s) { return s == null ? "" : s; }

    private String progressName(Integer progress) {
        if (progress == null) return "未知";
        switch (progress) {
            case 1: return "上门";
            case 2: return "量房";
            case 3: return "设计";
            case 4: return "报价";
            case 5: return "合同";
            case 6: return "施工";
            case 7: return "完工";
            case 8: return "结单";
            default: return "未知";
        }
    }

    @Override
    public List<ProjectStagePointDTO> listCurrentProjectStages() {
        LambdaQueryWrapper<Project> wrapper = new LambdaQueryWrapper<Project>()
                .eq(Project::getDeleted, 0);
        if (!SecurityUtils.hasRole("ADMIN") && !SecurityUtils.hasRole("ROLE_ADMIN")) {
            wrapper.eq(Project::getDesignerId, SecurityUtils.getUserId());
        }
        return this.list(wrapper).stream().map(p -> {
            ProjectStagePointDTO dto = new ProjectStagePointDTO();
            dto.setProjectId(p.getId());
            dto.setProjectName(p.getProjectName());
            dto.setProgress(p.getProgress());
            dto.setProgressName(progressName(p.getProgress()));
            return dto;
        }).collect(Collectors.toList());
    }

    @Override
    public List<ProgressCountDTO> countProjectsByProgress() {
        // 预先统计每个进度的数量，1..8；按数据范围过滤
        List<ProgressCountDTO> result = new java.util.ArrayList<>();
        for (int p = 1; p <= 8; p++) {
            LambdaQueryWrapper<Project> wrapper = new LambdaQueryWrapper<Project>()
                    .eq(Project::getDeleted, 0)
                    .eq(Project::getProgress, p);
            if (!SecurityUtils.hasRole("ADMIN") && !SecurityUtils.hasRole("ROLE_ADMIN")) {
                wrapper.eq(Project::getDesignerId, SecurityUtils.getUserId());
            }
            long count = this.count(wrapper);
            ProgressCountDTO dto = new ProgressCountDTO();
            dto.setProgress(p);
            dto.setProgressName(progressName(p));
            dto.setCount(count);
            result.add(dto);
        }
        return result;
    }

    /**
     * 生成项目名称
     */
    private String generateProjectName(ProjectDTO projectDTO) {
        return projectDTO.getCustomerName() + " - " +
                projectDTO.getCommunityName() + " - " +
                (projectDTO.getHouseType() != null ? projectDTO.getHouseType() : "未知户型");
    }

    /**
     * 验证期房日期
     */
    private void validateFutureHouseDate(ProjectDTO projectDTO) {
        // 如果是期房，必须填写期房日期
        if (projectDTO.getIsFutureHouse() == 1 && projectDTO.getFutureHouseDate() == null) {
            throw new ServiceException("期房必须填写预计交房日期");
        }

        // 如果不是期房，期房日期必须为空
        if (projectDTO.getIsFutureHouse() == 0 && projectDTO.getFutureHouseDate() != null) {
            projectDTO.setFutureHouseDate(null);
        }
    }

    /**
     * 验证项目名称是否需要变更
     */
    private boolean isProjectNameChanged(Project existingProject, ProjectDTO projectDTO) {
        return !existingProject.getCustomerName().equals(projectDTO.getCustomerName()) ||
                !existingProject.getCommunityName().equals(projectDTO.getCommunityName()) ||
                (existingProject.getHouseType() == null ? !"未知户型".equals(projectDTO.getHouseType()) :
                        !existingProject.getHouseType().equals(projectDTO.getHouseType()));
    }

    /**
     * 验证权限
     */
    private void validatePermission(Project project) {
        // 管理员可以查看所有项目
        if (SecurityUtils.hasRole("ADMIN")) {
            return;
        }

        // 设计师只能查看自己的项目
        Long currentUserId = SecurityUtils.getUserId();
        if (!currentUserId.equals(project.getDesignerId())) {
            throw new ServiceException("没有权限访问该项目");
        }
    }

    /**
     * 转换DTO为实体
     */
    private Project convertToEntity(ProjectDTO dto) {
        // 实际项目中可以使用MapStruct进行转换
        Project entity = new Project();
        entity.setProjectNo(dto.getProjectNo());
        entity.setProjectName(dto.getProjectName());
        entity.setCustomerName(dto.getCustomerName());
        entity.setPhone(dto.getPhone());
        entity.setGender(dto.getGender());
        entity.setDesignerId(dto.getDesignerId());
        entity.setDesignerName(dto.getDesignerName());
        entity.setProvince(dto.getProvince());
        entity.setCity(dto.getCity());
        entity.setDistrict(dto.getDistrict());
        entity.setCommunityName(dto.getCommunityName());
        entity.setDetailAddress(dto.getDetailAddress());
        entity.setBindH5Account(dto.getBindH5Account());
        entity.setH5UserId(dto.getH5UserId());
        entity.setH5UserName(dto.getH5UserName());
        entity.setCustomerSource(dto.getCustomerSource());
        entity.setProjectType(dto.getProjectType());
        entity.setBusinessType(dto.getBusinessType());
        entity.setIsFutureHouse(dto.getIsFutureHouse());
        entity.setFutureHouseDate(dto.getFutureHouseDate());
        entity.setHouseType(dto.getHouseType());
        entity.setHouseStyle(dto.getHouseStyle());
        entity.setBuildingArea(dto.getBuildingArea());
        entity.setPracticalArea(dto.getPracticalArea());
        entity.setHasWechat(dto.getHasWechat());
        entity.setWechatNo(dto.getWechatNo());
        entity.setConstructionProjectId(dto.getConstructionProjectId());
        entity.setConstructionProjectName(dto.getConstructionProjectName());
        entity.setDesignProjectId(dto.getDesignProjectId());
        entity.setDesignProjectName(dto.getDesignProjectName());
        entity.setRemark(dto.getRemark());
        entity.setProgress(dto.getProgress());
        entity.setFollowStatus(dto.getFollowStatus());
        entity.setLatestRecord(dto.getLatestRecord());
        return entity;
    }

    /**
     * 转换实体为DTO
     */
    private ProjectDTO convertToEntity(Project entity) {
        // 实际项目中可以使用MapStruct进行转换
        ProjectDTO dto = new ProjectDTO();
        dto.setId(entity.getId());
        dto.setProjectNo(entity.getProjectNo());
        dto.setProjectName(entity.getProjectName());
        dto.setCustomerName(entity.getCustomerName());
        dto.setPhone(entity.getPhone());
        dto.setGender(entity.getGender());
        dto.setDesignerId(entity.getDesignerId());
        dto.setDesignerName(entity.getDesignerName());
        dto.setProvince(entity.getProvince());
        dto.setCity(entity.getCity());
        dto.setDistrict(entity.getDistrict());
        dto.setCommunityName(entity.getCommunityName());
        dto.setDetailAddress(entity.getDetailAddress());
        dto.setBindH5Account(entity.getBindH5Account());
        dto.setH5UserId(entity.getH5UserId());
        dto.setH5UserName(entity.getH5UserName());
        dto.setCustomerSource(entity.getCustomerSource());
        dto.setProjectType(entity.getProjectType());
        dto.setBusinessType(entity.getBusinessType());
        dto.setIsFutureHouse(entity.getIsFutureHouse());
        dto.setFutureHouseDate(entity.getFutureHouseDate());
        dto.setHouseType(entity.getHouseType());
        dto.setHouseStyle(entity.getHouseStyle());
        dto.setBuildingArea(entity.getBuildingArea());
        dto.setPracticalArea(entity.getPracticalArea());
        dto.setHasWechat(entity.getHasWechat());
        dto.setWechatNo(entity.getWechatNo());
        dto.setConstructionProjectId(entity.getConstructionProjectId());
        dto.setConstructionProjectName(entity.getConstructionProjectName());
        dto.setDesignProjectId(entity.getDesignProjectId());
        dto.setDesignProjectName(entity.getDesignProjectName());
        dto.setRemark(entity.getRemark());
        dto.setProgress(entity.getProgress());
        dto.setFollowStatus(entity.getFollowStatus());
        dto.setLatestRecord(entity.getLatestRecord());
        dto.setCreateTime(entity.getCreateTime());
        return dto;
    }
}